package com.app.backend.activiti.controller;

import com.app.backend.activiti.entity.ActModel;
import com.app.backend.activiti.entity.ActProcess;
import com.app.backend.activiti.service.ActModelService;
import com.app.backend.activiti.service.ActProcessService;
import com.app.backend.common.response.BaseResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.List;

import static com.app.backend.common.response.ResponseCode.*;

/**
 * @program: ActModelController
 * @description:
 * @author: Zhun.Xiao
 * @create: 2020-02-27 09:50
 **/

@Slf4j
@RestController
@Api("流程模板管理")
@RequestMapping("/api/v1/act/model")
public class ActModelController {
    @Autowired
    private ActModelService actModelService;

    @Autowired
    private ActProcessService actProcessService;
    @Autowired
    RepositoryService repositoryService;

    @Autowired
    ObjectMapper objectMapper;

    //创建模型，当前通过页面访问创建并保存model。正式环境下需改成前后端分离模式
    @RequestMapping(value = "/create", method = RequestMethod.GET)
    @ApiOperation(value = "创建模型")
    public void create(HttpServletRequest request, HttpServletResponse response) {
        try {

            ActModel actModel = new ActModel();
            actModel.setDescription("test_model_desc");
            actModel.setName("test_model_name");
            actModel.setModelKey("test_model_key");

            // 初始化一个空模型
            Model model = repositoryService.newModel();

            ObjectNode modelNode = objectMapper.createObjectNode();
            modelNode.put(ModelDataJsonConstants.MODEL_NAME, actModel.getName());
            modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, actModel.getDescription());
            modelNode.put(ModelDataJsonConstants.MODEL_REVISION, model.getVersion());

            model.setName(actModel.getName());
            model.setKey(actModel.getModelKey());
            model.setMetaInfo(modelNode.toString());

            // 保存模型
            repositoryService.saveModel(model);
            String id = model.getId();

            // 完善ModelEditorSource
            ObjectNode editorNode = objectMapper.createObjectNode();
            ObjectNode stencilSetNode = objectMapper.createObjectNode();
            ObjectNode properties = objectMapper.createObjectNode();
            stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
            editorNode.replace("stencilset", stencilSetNode);
            properties.put("process_id", actModel.getModelKey());
            editorNode.replace("properties", properties);
            try {
                repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
            } catch (UnsupportedEncodingException e) {
                log.error(e.toString());
                log.error("创建模型失败");
                return;
            }

            // 保存扩展模型至数据库
            actModel.setId(id);
            actModel.setVersion(model.getVersion());
            actModelService.save(actModel);

            log.info("添加模型成功");

            //非前后端分离情况下直接跳转到模型编辑页面
            //todo 正式情况下改为前后端分离，由前端跳转
            response.sendRedirect(request.getContextPath() + "/modeler.html?modelId=" + id);
        } catch (Exception e) {
            System.out.println("创建模型失败：");
        }

    }

    @PostMapping(value = "/deploy")
    @ApiOperation(value = "部署发布模型")
    public BaseResponse deploy(@RequestParam String id) {
        // 获取模型
        Model modelData = repositoryService.getModel(id);
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());

        if (bytes == null) {
            return new BaseResponse(PARAM_FAIL, "模型参数为空");
        }

        try {
            JsonNode modelNode = new ObjectMapper().readTree(bytes);

            BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
            if (model.getProcesses().size() == 0) {
                return new BaseResponse(PARAM_FAIL, "模型至少需啊哟一条主流程");
            }
            byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);

            // 部署发布模型流程
            String processName = modelData.getName() + ".bpmn20.xml";
            Deployment deployment = repositoryService.createDeployment()
                    .name(modelData.getName())
                    .addString(processName, new String(bpmnBytes, "UTF-8"))
                    .deploy();

            // 设置流程分类 保存扩展流程至数据库
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
            ActModel actModel = actModelService.get(id);
            for (ProcessDefinition pd : list) {
                ActProcess actProcess = new ActProcess();
                actProcess.setId(pd.getId());
                actProcess.setName(modelData.getName());
                actProcess.setProcessKey(modelData.getKey());
                actProcess.setDeploymentId(deployment.getId());
                actProcess.setDescription(actModel.getDescription());
                actProcess.setVersion(pd.getVersion());
                actProcess.setXmlName(pd.getResourceName());
                actProcess.setDiagramName(pd.getDiagramResourceName());
                actProcessService.setAllOldByProcessKey(modelData.getKey());
                actProcess.setLatest(true);
                actProcessService.save(actProcess);
            }
        } catch (Exception e) {
            log.error(e.toString());
            return new BaseResponse(SYSTEM_ERROR, "部署失败");
        }

        return new BaseResponse(SUCCESS, "部署成功");
    }


    @PostMapping(value = "/delModels")
    @ApiOperation(value = "通过id批量删除模型")
    public BaseResponse deleteModelByIds(@RequestParam String[] ids) {
        for (String id : ids) {
            repositoryService.deleteModel(id);
            actModelService.deleteById(id);
        }
        return new BaseResponse("模型删除成功");
    }

    //todo deployByFile - 通过文件部署模型 ，即支持导入模型 - 优先级低
    @RequestMapping(value = "/deployByFile", method = RequestMethod.POST)
    @ApiOperation(value = "通过文件部署模型")
    public BaseResponse deployByFile(@RequestParam MultipartFile file) {

        return null;
    }

    //todo export - 导出模型XML - 优先级低
    @RequestMapping(value = "/export", method = RequestMethod.POST)
    @ApiOperation(value = "导出模型XML")
    public void export(@RequestParam String id, HttpServletResponse response) {
    }


}